package com.ehe.common.core.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ehe.common.core.mybatis.pagination.MyPageImpl;
import com.ehe.common.core.web.dao.SuperMapper;
import com.ehe.common.core.web.pojo.domain.SuperEntity;
import com.ehe.common.core.web.pojo.dto.BaseSearchable;
import com.ehe.common.core.web.service.MybatisService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.CollectionUtils;

import javax.annotation.Nonnull;
import java.io.Serializable;
import java.util.*;
import java.util.function.LongFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class MybatisServiceImpl<T extends SuperEntity<T, PK>, PK extends Serializable> implements MybatisService<T, PK> {

    /** 项目配置文件 */
//    @Autowired
//    private CoreProperties coreProperties;

    /**
     * 子类实现该方法，获取泛型对应的mapper
     * @return 泛型mapper
     */
    protected abstract SuperMapper<T> getSuperMapper();

    @Override
    public QueryWrapper<T> createQueryWrapper() {
        return new QueryWrapper<>();
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(Pageable pageable) {
        return createQueryWrapper(pageable.getSort());
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(Sort sort) {
        return addQueryWrapper(createQueryWrapper(), sort);
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(BaseSearchable baseSearchable) {
        return addQueryWrapper(createQueryWrapper(), baseSearchable);
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(Pageable pageable, BaseSearchable baseSearchable) {
        return createQueryWrapper(pageable.getSort(), baseSearchable);
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(Sort sort, BaseSearchable baseSearchable) {
        return addQueryWrapper(createQueryWrapper(baseSearchable), sort);
    }

    @Override
    public QueryWrapper<T> addQueryWrapper(QueryWrapper<T> queryWrapper, @Nonnull Pageable pageable) {
        return addQueryWrapper(queryWrapper, pageable.getSort());
    }

    @Override
    public QueryWrapper<T> addQueryWrapper(QueryWrapper<T> queryWrapper, @Nonnull Sort sort) {
        if (sort.isUnsorted()) {
//            queryWrapper.lambda().orderByAsc(T::getModifiedAt);
            queryWrapper.orderByDesc("modified_at");
            return queryWrapper;
        }
        sort.forEach(order -> {
            // 驼峰转下划线
            String property = com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(order.getProperty());
            queryWrapper.orderBy(true, order.isAscending(), property);
        });
        return queryWrapper;
    }

    @Override
    public QueryWrapper<T> addQueryWrapper(QueryWrapper<T> queryWrapper, BaseSearchable baseSearchable) {
        addQueryWrapper(queryWrapper.lambda(), baseSearchable);
        return queryWrapper;
    }

    @Override
    public void addQueryWrapper(LambdaQueryWrapper<T> lambdaQueryWrapper, BaseSearchable baseSearchable) {

    }

    @Override
    public int insert(T entity) {
        return getSuperMapper().insert(entity);
    }

    @Override
    public int insertBatchSomeColumn(List<T> entityList) {
        return getSuperMapper().insertBatchSomeColumn(entityList);
    }

    @Override
    public int insertBatch(List<T> entityList) {
        //coreProperties.getMyBatis().getBatchLimit()
        return insertBatch(entityList, 2000);
    }

    @Override
    public int insertBatch(List<T> entityList, int limit) {
        long slices = (long) Math.ceil((double) entityList.size() / limit);
        LongFunction<List<T>> longFunction = a -> entityList.stream().skip(a * limit).limit(limit).parallel().collect(Collectors.toList());
        return Stream.iterate(0L, n -> n + 1).limit(slices)
                .map(longFunction::apply)
                .mapToInt(getSuperMapper()::insertBatchSomeColumn)
                .sum();
    }

    @Override
    public int deleteById(PK id) {
        return getSuperMapper().deleteById(id);
    }

    @Override
    public int deleteByMap(Map<String, Object> columnMap) {
        return getSuperMapper().deleteByMap(columnMap);
    }

    @Override
    public int delete(Wrapper<T> wrapper) {
        return getSuperMapper().delete(wrapper);
    }

    @Override
    public int deleteBatchIds(Collection<? extends PK> idList) {
        return getSuperMapper().deleteBatchIds(idList);
    }

    @Override
    public int updateById(T entity) {
        return getSuperMapper().updateById(entity);
    }

    @Override
    public int update(T entity, Wrapper<T> updateWrapper) {
        return getSuperMapper().update(entity, updateWrapper);
    }

    @Override
    public int alwaysUpdateSomeColumnById(T entity) {
        return getSuperMapper().alwaysUpdateSomeColumnById(entity);
    }

    @Override
    public T selectById(PK id) {
        return getSuperMapper().selectById(id);
    }

    @Override
    public Optional<T> selectByIdOptional(PK id) {
        return Optional.ofNullable(selectById(id));
    }

    @Override
    public List<T> selectBatchIds(Collection<? extends PK> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new ArrayList<>();
        }
        return getSuperMapper().selectBatchIds(idList);
    }

    @Override
    public List<T> selectByMap(Map<String, Object> columnMap) {
        return getSuperMapper().selectByMap(columnMap);
    }

    @Override
    public T selectOne(Sort sort, BaseSearchable baseSearchable) {
        return getSuperMapper().selectOne(createQueryWrapper(sort, baseSearchable));
    }

    @Override
    public Optional<T> selectOneOptional(Sort sort, BaseSearchable baseSearchable) {
        return Optional.ofNullable(selectOne(sort, baseSearchable));
    }

    @Override
    public T selectOne(Wrapper<T> queryWrapper) {
        return getSuperMapper().selectOne(queryWrapper);
    }

    @Override
    public Optional<T> selectOneOptional(Wrapper<T> queryWrapper) {
        return Optional.ofNullable(selectOne(queryWrapper));
    }

    @Override
    public Integer selectCount(BaseSearchable baseSearchable) {
        return getSuperMapper().selectCount(createQueryWrapper(baseSearchable));
    }

    @Override
    public Integer selectCount(Wrapper<T> queryWrapper) {
        return getSuperMapper().selectCount(queryWrapper);
    }

    @Override
    public List<T> selectList(BaseSearchable baseSearchable) {
        QueryWrapper<T> queryWrapper = createQueryWrapper(baseSearchable);
        return getSuperMapper().selectList(queryWrapper);
    }

    @Override
    public List<T> selectList(Sort sort, BaseSearchable baseSearchable) {
        QueryWrapper<T> queryWrapper = createQueryWrapper(sort, baseSearchable);
        return getSuperMapper().selectList(queryWrapper);
    }

    @Override
    public List<T> selectList(Wrapper<T> queryWrapper) {
        return getSuperMapper().selectList(queryWrapper);
    }

    @Override
    public Page<T> selectPage(Pageable pageable, BaseSearchable baseSearchable) {
        return getSuperMapper().selectMyPage(MyPageImpl.of(pageable), createQueryWrapper(pageable, baseSearchable)).convertPage();
    }

    @Override
    public Page<T> selectPage(Pageable pageable) {
        return getSuperMapper().selectMyPage(MyPageImpl.of(pageable), createQueryWrapper(pageable)).convertPage();
    }
}
